<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="S1cDe" id="S1cDe"><span data-lake-id="u822221f7" id="u822221f7">典型回答</span></h1>
  <p data-lake-id="u8a5171ea" id="u8a5171ea"><br></p>
  <p data-lake-id="ue880624f" id="ue880624f"><span data-lake-id="ubdb7967e" id="ubdb7967e">提到多级缓存，很多人第一时间想到通过Guava本地缓存+Redis分布式缓存组成的二级缓存。其实，多级缓存可并不只是这两层，在一些场景中，可能有很多层。</span></p>
  <p data-lake-id="u41ada7e0" id="u41ada7e0"><span data-lake-id="ud9970b66" id="ud9970b66">​</span><br></p>
  <p data-lake-id="ubd1caed1" id="ubd1caed1"><span data-lake-id="u29eac751" id="u29eac751">我们在下面这篇中介绍过，近端缓存的概念，我们提到"</span><strong><span data-lake-id="ubdee5fda" id="ubdee5fda">近端缓存（Edge Cache）通常是指位于网络边缘、离用户更近的位置的缓存。</span></strong><span data-lake-id="u8ff2dfba" id="u8ff2dfba">"那么，我们以一个电商的秒杀场景举例，说一说一个多级缓存的真实应用场景。</span></p>
  <p data-lake-id="u2cc4d070" id="u2cc4d070"><span data-lake-id="u0363f467" id="u0363f467">​</span><br></p>
  <p data-lake-id="uc045c215" id="uc045c215"><br></p>
  <p data-lake-id="u54b3c276" id="u54b3c276"><strong><span data-lake-id="u4498369c" id="u4498369c">一个真实的秒杀业务，从前到后，可能涉及到5层缓存。</span></strong></p>
  <p data-lake-id="u4aaeee1b" id="u4aaeee1b"><strong><span data-lake-id="uae4bc60f" id="uae4bc60f">​</span></strong><br></p>
  <p data-lake-id="udca3895a" id="udca3895a"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1685247046917-ffecd927-b27d-4cea-949a-feb093ad3a7c.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_48%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u25efaee3" id="u25efaee3"><br></p>
  <h3 data-lake-id="EmWr7" id="EmWr7"><span data-lake-id="u1468da31" id="u1468da31">客户端缓存</span></h3>
  <p data-lake-id="u0b9a50fb" id="u0b9a50fb"><br></p>
  <p data-lake-id="u0e476cf9" id="u0e476cf9"><span data-lake-id="uced78a52" id="uced78a52">首先，离用户最近的一定是客户端了，比如我们使用的手机、电脑等，在手机上的APP以及电脑的浏览器 ，都是可以支持做缓存的。</span></p>
  <p data-lake-id="u7d9eaa7e" id="u7d9eaa7e"><span data-lake-id="u5703f3dd" id="u5703f3dd">​</span><br></p>
  <p data-lake-id="ua96b6c8a" id="ua96b6c8a"><span data-lake-id="uaf038c16" id="uaf038c16">秒杀场景中，比较典型的客户端缓存的例子就是秒杀页面的倒计时。</span></p>
  <p data-lake-id="u12512230" id="u12512230"><span data-lake-id="u2cac2b93" id="u2cac2b93">​</span><br></p>
  <p data-lake-id="u704afafc" id="u704afafc"><span data-lake-id="u70cd1458" id="u70cd1458">当用户第一次访问秒杀页面的时候，会向后端服务器请求查询秒杀开始时间，然后这个时间就可以在客户端进行缓存下来了。</span></p>
  <p data-lake-id="u9d5cc96c" id="u9d5cc96c"><span data-lake-id="ue581e2ab" id="ue581e2ab">​</span><br></p>
  <p data-lake-id="u9a49d135" id="u9a49d135"><span data-lake-id="uab3f8360" id="uab3f8360">然后客户端自己就可以基于这个开始时间做倒计时了。</span></p>
  <p data-lake-id="u602cc641" id="u602cc641"><span data-lake-id="u3afa552d" id="u3afa552d">​</span><br></p>
  <p data-lake-id="ud24b34c4" id="ud24b34c4"><span data-lake-id="u15909a05" id="u15909a05">设想一下，如果每一秒钟都要向后端发送请求，那么请求量实在是太大了，所以通过客户端缓存的方式，可以大大降低后端服务器的压力。</span></p>
  <h3 data-lake-id="MkzR6" id="MkzR6"><span data-lake-id="u23829ad9" id="u23829ad9">CDN缓存</span></h3>
  <p data-lake-id="ub0bf5b7a" id="ub0bf5b7a"><br></p>
  <p data-lake-id="u527e25bd" id="u527e25bd"><span data-lake-id="u8d44564d" id="u8d44564d">秒杀活动中，有很多商品相关的信息，比如商品的图片信息，这些前端的静态资源其实变化的频率并不是很高，那么其实就可以通过CDN来做缓存。</span></p>
  <p data-lake-id="u5c72ef55" id="u5c72ef55"><span data-lake-id="ue3205292" id="ue3205292">​</span><br></p>
  <p data-lake-id="ue8a1871b" id="ue8a1871b"><span data-lake-id="u2c012d6b" id="u2c012d6b">这些静态资源，如图像、HTML、JavaScript 和视频。提前放到CDN中，让用户可以就近的访问到CDN快速的拿到静态资源。</span></p>
  <p data-lake-id="uf395f26f" id="uf395f26f"><br></p>
  <p data-lake-id="u9c5e286c" id="u9c5e286c"><span data-lake-id="u3703c3f7" id="u3703c3f7">关于什么是CDN，以及为什么他能作缓存，为啥他比应用服务器更快，我们在下面的题目中单独展开：</span></p>
  <p data-lake-id="ub4005c07" id="ub4005c07"><span data-lake-id="u3196d0ed" id="u3196d0ed">​</span><br></p>
  <p data-lake-id="u5d27f967" id="u5d27f967"><br></p>
  <h3 data-lake-id="xurYU" id="xurYU"><span data-lake-id="uddb733f9" id="uddb733f9">Nginx缓存</span></h3>
  <p data-lake-id="ub64a42eb" id="ub64a42eb"><br></p>
  <p data-lake-id="uc063fbd5" id="uc063fbd5"><span data-lake-id="u6f5d52d0" id="u6f5d52d0">在客户端及CDN缓存的基本都一些静态的数据，但是还是有很多数据不适合做缓存的，那么这时候用户请求过来的话就要发送到后端服务器中。</span></p>
  <p data-lake-id="u3abf877f" id="u3abf877f"><span data-lake-id="u033e5b4f" id="u033e5b4f">​</span><br></p>
  <p data-lake-id="u477dfde9" id="u477dfde9"><span data-lake-id="u24c19041" id="u24c19041">而在请求给到服务器之前，会先经过Nginx做负载均衡。</span></p>
  <p data-lake-id="u5c24388d" id="u5c24388d"><span data-lake-id="u4284890e" id="u4284890e">​</span><br></p>
  <p data-lake-id="u8adb2375" id="u8adb2375"><span data-lake-id="u3135c829" id="u3135c829">为了提升请求的效率，降低对后端服务器的压力，很多时候我们也会在Nginx中做一些缓存。</span></p>
  <p data-lake-id="uf730cd72" id="uf730cd72"><span data-lake-id="ubd16ba9b" id="ubd16ba9b">​</span><br></p>
  <p data-lake-id="u5ad7a8a0" id="u5ad7a8a0"><span data-lake-id="u0dbad03d" id="u0dbad03d">比如一些静态资源，除了放到CDN中，Nginx中也可以缓存一份，当没有CDN的时候，可以优先到Nginx中获取。</span></p>
  <p data-lake-id="uabeb2393" id="uabeb2393"><span data-lake-id="ue8d57415" id="ue8d57415">​</span><br></p>
  <p data-lake-id="u5e7677a4" id="u5e7677a4"><span data-lake-id="u46cb2f50" id="u46cb2f50">在秒杀场景中，我们需要做一些用户的鉴权，比如用户是否登录，是否是黄牛用户，用户的IP是否被封禁。这些信息一般是放在Nginx中的，可以在这里面做一些前置的校验，把一些非法的请求就直接都给拒绝掉了。</span></p>
  <p data-lake-id="ud237877d" id="ud237877d"><br></p>
  <h3 data-lake-id="qxwCC" id="qxwCC"><span data-lake-id="uf0d597ca" id="uf0d597ca">Web App 缓存</span></h3>
  <p data-lake-id="u88548233" id="u88548233"><br></p>
  <p data-lake-id="uf175a7da" id="uf175a7da"><span data-lake-id="ud5b56d48" id="ud5b56d48">当Nginx请求过滤之后，有些合理请求就需要发送到Web App当中，这时候就会涉及到很多具体的业务逻辑了。</span></p>
  <p data-lake-id="u566490d4" id="u566490d4"><br></p>
  <p data-lake-id="uc80ee73a" id="uc80ee73a"><span data-lake-id="u396e94cd" id="u396e94cd">但是，应用当中也会经常使用本地缓存来提升查询效率。但是本地缓存我们都知道，可能存在不一致的问题，所以这里面存储的信息一般是变化没那么频繁的。</span></p>
  <p data-lake-id="ub266f0b5" id="ub266f0b5"><span data-lake-id="ueed2720f" id="ueed2720f">​</span><br></p>
  <p data-lake-id="ud0ff7c76" id="ud0ff7c76"><span data-lake-id="ua1153c00" id="ua1153c00">比如一次秒杀活动的开始和结束时间、比如秒杀的用户的用户等级这些信息，基本都是变化没那么频繁的，就可以放到本地缓存中，可以快速的读取。</span></p>
  <p data-lake-id="ua4c2586e" id="ua4c2586e"><br></p>
  <h3 data-lake-id="pt2Qa" id="pt2Qa"><span data-lake-id="u309cd080" id="u309cd080">分布式缓存</span></h3>
  <p data-lake-id="ua3ef9045" id="ua3ef9045"><br></p>
  <p data-lake-id="ua78fb900" id="ua78fb900"><span data-lake-id="uc8da9406" id="uc8da9406">有些数据因为要考虑他的一致性，所以没办法放到本地缓存中，比如商品库存，这种就需要放到分布式缓存中，比如Redis。</span></p>
  <p data-lake-id="ubfeac397" id="ubfeac397"><span data-lake-id="u068af51d" id="u068af51d">​</span><br></p>
  <p data-lake-id="u5140bed5" id="u5140bed5"><span data-lake-id="u16afdfbf" id="u16afdfbf">在秒杀场景中，我们经常使用Redis来做库存扣减，其实这就是利用了Redis来做缓存的一种具体案例。</span></p>
  <p data-lake-id="ue2ae52dc" id="ue2ae52dc"><span data-lake-id="uaa4b386c" id="uaa4b386c">​</span><br></p>
  <p data-lake-id="ubed59b27" id="ubed59b27"><span data-lake-id="u0aaf6b92" id="u0aaf6b92">​</span><br></p>
  <p data-lake-id="ub6868521" id="ub6868521"><span data-lake-id="ud6cdad79" id="ud6cdad79">以上，从前到后串联了下秒杀业务的多级缓存的实现，关于秒杀的其他问题，大家可以参考：</span></p>
  <p data-lake-id="u5666b887" id="u5666b887"><span data-lake-id="ud6cfbf11" id="ud6cfbf11">​</span><br></p>
 </body>
</html>